import axios from 'axios';
import qs from 'qs';
import jsonp from 'jsonp';
import _ from 'lodash';
import pathToRegexp from 'path-to-regexp';
import { message } from 'antd';
import config from '../configs/config';
import { subscribe, queueControl } from './util';

let waittingQueue = [];
let permissions = [];
subscribe((state) => {
	const newPermissions = _.get(state, 'app.user.permissions', []);
	if (!permissions.length && newPermissions.length) {
		permissions = newPermissions;
		waittingQueue.forEach(o => {
			request(o.options).then(o.res).catch(o.ret);
		});
		waittingQueue = [];
	}
});

export function getVersion(path) {
	let version = '1.0';
	try {
		if (path.includes(config.apiPrefix)) path = path.replace(config.apiPrefix, '');
		const permission = permissions.find(p => p.uri === path);
		if (permission) version = _.get(permissions.find(p => !p.uri && p.pPermissionId === permission.id), 'versionCode') || version;
	} catch (error) {
		console.error('获取接口版本出错', error);
	}
	return version;
}

function realFetch(options) {
	const { fetchType, method = 'get', ...opt } = options;
	let { url, data } = options;
	delete opt.data;
	delete opt.url;

	axios.defaults.headers.common.Authorization = window.localStorage.getItem('access_token');
	const path = url.replace(config.apiPrefix, '');
	const cloneData = {
		appKey: config.appKey,
		data: _.cloneDeep(data),
		version: getVersion(path)
	};
	if (typeof cloneData.data === 'undefined') delete cloneData.data;

	opt.headers = { ...opt.headers, Version: cloneData.version };

	try {
		let domin = '';
		// if (process.env.NODE_ENV === 'production') {
		// 	domin = 'backend';
		// }
		if (url.match(/[a-zA-z]+:\/\/[^/]*/)) {
			domin = url.match(/[a-zA-z]+:\/\/[^/]*/)[0];
			url = url.slice(domin.length);
		}
		const match = pathToRegexp.parse(url);
		url = pathToRegexp.compile(url)(data);
		for (const item of match) {
			if (item instanceof Object && item.name in cloneData) {
				delete cloneData[item.name];
			}
		}
		url = domin + url;
	} catch (e) {
		message.error(e.message);
	}

	if (fetchType === 'JSONP') {
		return new Promise((resolve, reject) => {
			jsonp(url, {
				param: `${qs.stringify(data)}&callback`,
				name: `jsonp_${new Date().getTime()}`,
				timeout: 4000,
			}, (error, result) => {
				if (error) {
					reject(error);
				}
				resolve({ statusText: 'OK', status: 200, data: result });
			});
		});
	} else if (fetchType === 'YQL') {
		url = `http://query.yahooapis.com/v1/public/yql?q=select * from json where url='${options.url}?${encodeURIComponent(qs.stringify(options.data))}'&format=json`;
		data = null;
	}

	switch (method.toLowerCase()) {
		case 'get':
			return axios.get(url, {
				params: cloneData,
			}, opt);
		case 'delete':
			return axios.delete(url, {
				data: cloneData,
			}, opt);
		case 'post':
			return axios.post(url, cloneData, opt);
		case 'put':
			return axios.put(url, cloneData, opt);
		case 'patch':
			return axios.patch(url, cloneData, opt);
		default:
			return axios(options);
	}
}

export const fetch = queueControl(realFetch);

export default function request(options) {
	const path = options.url.replace(config.apiPrefix, '');
	if (!permissions.length && !config.whitelist.includes(path)) { // 权限列表还没有返回，无法确定versionCode，所以要等
		return new Promise((res, ret) => {
			waittingQueue.push({ res, ret, options });
		});
	}

	let cross = false; // 是否跨域请求
	if (options.url && options.url.indexOf('//') > -1) {
		const origin = `${options.url.split('//')[0]}//${options.url.split('//')[1].split('/')[0]}`;
		cross = window.location.origin !== origin;
		if (cross) {
			if (config.CORS && config.CORS.indexOf(origin) > -1) {
				options.fetchType = 'CORS';
			} else if (config.YQL && config.YQL.indexOf(origin) > -1) {
				options.fetchType = 'YQL';
			} else {
				options.fetchType = 'JSONP';
			}
		}
	}
	return fetch(options).then((response) => {
		// console.log('123', options.url, response);
		const { statusText, status } = response;
		const data = options.fetchType === 'YQL' ? response.data.query.results.json : response.data;
		if (!cross) {
			data.data = (typeof data.data === 'string' && data.data.includes('{')) ? JSON.parse(data.data) : data.data;
		}
		return {
			success: true,
			message: statusText,
			statusCode: status,
			...data
		};
	}).catch((error) => {
		const { response } = error;
		let msg;
		let statusCode;
		if (response && response instanceof Object) {
			const { data, statusText } = response;
			statusCode = response.status;
			msg = data.message || statusText;
		} else {
			statusCode = 600;
			msg = error.message || 'Network Error';
		}
		return { success: false, statusCode, message: msg };
	});
}

export const generator = url => data => request({
	method: 'post',
	url,
	data,
});
